Assignment Three: The Week Four Assignment

WDI and ggplot2

  • Create an R Notebook of a Data Analysis containing the following and submit the rendered HTML file (eg. a3_123456.nb.html by replacing 123456 with your ID)
    1. create an R Notebook using the R Notebook Template in Moodle, save as a3_123456.Rmd,
    2. write your name and ID and the contents,
    3. run each code block,
    4. preview to create a3_123456.nb.html,
    5. submit a3_123456.nb.html to Moodle.
  1. Choose at least one indicator of WDI

    • Information of the data: Name, Indicator, Description, Source, etc.
    • Download the data with WDI
    • Explain why you chose the indicator
    • List questions you want to study
  2. Explore the data using visualization using ggplot2

    • Use a histogram (geom_histogram), boxplot (geom_boxplot), a scatter plot (geom_point), a line plot (geom_line)
    • For at least one chart, add title, and labels of axis, and add an explanation of it
  3. Observations and difficulties encountered.

Due: 2023-01-16 23:59:00. Submit your R Notebook file in Moodle (The Third Assignment). Due on Monday!

1 Set up

Follow thw workflow explained in EDA4 on January 18.

1.1 EDA by R Studio: Step 1

In RStudio,

1.1. Project

  • Create a new project: File > New Project; or
  • Open a project: File > Open Project, Open Project in New Session, Open Recent Project
    • It is easier to find an existing project from: File > Recent Project
  • Check there is a file project_name.Rproj in your project folder (directory)

1.2. data folder (directory) data

  • Create a data folder: Press New Folder at the right bottom pane; or
  • Confirm the data folder previously created: Press Files at the right bottom pane
  • If you follow 1, the data folder exists in your project folder

1.3. Move (or copy) data for the project to the data folder

  • If you downloaded the data, it is in your Download folder. Move it to data.
  • Check in your RStudio that your data is in data: Press Files at the right bottom pane and click data, the data folder.

1.2 EDA by R Studio: Step 2

2.1. Project Notebook: Memo

  • Create an R Notebook: File > New File > R Notebook

    • You can use R Notebook template in Moodle by moving the template (template.Rmd or template.nb.Rmd) file in your project folder or copy and paste the text file into your new R Notebook.
    • If you use template.nb.Rmd (R Notebook File), choose Open in Editor.
  • Add descriptive title.

2.2. Setup Code Chunk

  • Create a code chunk and add packages to use in the project and RUN the code.

    • library(tidyverse)
    • library(WDI)
    • or any other packages
library(tidyverse)
library(WDI)

When people read a paper, they want to know the minimal set of packages required to install. So it is better to load the packages by library() you actually need in the paper.

2.3. Choose Source or Visual editor mode, and start editing Project Notebook

  • Set up Headings such as: About, Data, Analysis and Visualizations, Conclusions
  • Under About or Data, paste url of the sites and/or the data

2.4. Edit a new file by saving as for a report

  • File > Save As…

2 General Comments

2.1 Varibles

We should know first about the variables. At least you must know if each of the variables is a categorical variable or a numerical variable.

2.2 Visualization

  • What type of variation occurs within my variables?
  • What type of covariation occurs between my variables?

3 World Development Indicators (WDI)

3.1 Setup

It is not a must, but it is good to run the following code chunk and use wdi_cache for WDIsearch() to update the mata data. See WDIcache help.

wdi_cache <- WDIcache()

3.2 Indicators Used in Assignment Three

  • NY.GDP.PCAP.KD: GDP per capita (constant 2015 US$)
  • NY.GDP.MKTP.CD: GDP (current US$)
  • NY.GDP.PCAP.KD.ZG: GDP per capita growth (annual%)
  • SP.POP.TOTL: Total Population
  • IP.JRN.ARTC.SC: Scientific and technical journal articles
  • FP.CPI.TOTL.ZG: Inflation, consumer prices (% annual growth)
  • DT.ODA.ODAT.PC.ZS: Net ODA received per capita (current US$)
  • BX.KLT.DINV.CD.WD: Foreign direct investment, net inflows (BoP, current US$)
  • MS.MIL.XPND.GD.ZS: Military expenditure (% of GDP)
  • MS.MIL.TOTL.P1: Total Armed Forces Personnel
  • SI.POV.MDIM: Multidimensional poverty headcount ratio (% of total population)
  • SI.POV.NAHC: Poverty headcount ratio at national poverty lines (% of population)
  • SI.POV.GINI: Gini index
  • NY.GNS.ICTR.ZS: Gross savings (% of GDP)
  • SL.UEM.TOTL.ZS: Unemployment, total (% of total labor force) (modeled ILO estimate)
  • SP.URB.TOTL.IN.ZS (Urban population (% of total population))
  • AG.LND.AGRI.ZS: Agricultural land (% of land area)
  • SE.ADT.LITR.FE.ZS: Literacy rate, adult female (% of females ages 15 and above))
  • SE.ADT.LITR.MA.ZS: Literacy rate, adult male (% of males ages 15 and above))
  • SE.ADT.LITR.ZS: Literacy rate, adult total
  • SE.ADT.1524.LT.FE.ZS: Literacy rate, youth female (% of females ages 15-24)
  • SE.XPD.TOTL.GD.ZS: Government expenditure on education, total (% of GDP)
  • SG.GEN.PARL.ZS: Proportion of seats held by women in national parliaments (%)

3.3 WDIsearch

We obtain the information of the data, i.e., meta data of WDI: Name, Indicator, Description, Source, etc. by WDIsearch.

  • Usage
WDIsearch(string = "gdp", field = "name", short = TRUE, cache = NULL)
  • Arguments

    • string: Character string. Search for this string using grep with ignore.case=TRUE.

    • field: Character string. Search this field. Admissible fields: ‘indicator’, ‘name’, ‘description’, ‘sourceDatabase’, ‘sourceOrganization’

    • short: TRUE: Returns only the indicator’s code and name. FALSE: Returns the indicator’s code, name, description, and source.

    • cache: Data list generated by the WDIcache function. If omitted, WDIsearch will search a local list of series.

If you follow the order of the arguments, you can omit argument names: string, field, short, cache.

  • The simplest format 1.
WDIsearch("NY.GNS.ICTR.ZS", "indicator")
  • The simplest format 2.
WDIsearch("Literacy rate", "name")
  • Detailed with short = FALSE
WDIsearch("IP.JRN.ARTC.SC", "indicator", FALSE)
  • You can use wdi_cache downloaded above to use the updated meta data.
WDIsearch("Government expenditure on education", "name", FALSE, wdi_cache)

3.4 Importing Data Using WDI

  • The shortest form. The following is same as: WDI(country = "all", indicator = "NY.GDP.PCAP.KD", start = 1960, end = NULL, extra = FALSE, cache = NULL, latest = NULL, language = "en)
WDI(indicator = "NY.GDP.PCAP.KD")
  • In order to use the downloaded data, we need to assign a name to it. It can be df if you download and use only one data, but it is better to assign the data to be a more descriptive name.
df_gdppcap <- WDI(indicator = "NY.GDP.PCAP.KD")
df_gdppcap
  • If you want to use extra information such as region, income, lending, use extra = TRUE.
df_gdppcap_extra <- WDI(indicator = "NY.GDP.PCAP.KD", extra = TRUE)
df_gdppcap_extra

3.5 Writing and reading a csv file

Since the data is generally huge, it is better to use a data saved in your computer. Before saving it check whether you have data folder (or directory) in you project folder. Use the Files tab of the right bottom pane. You should be able to see the project icon with Rproj at the end, your R Notebook file you are editing, and the data folder. Since .csv is automatically added, write_csv(gdppcap_extra, "data/gdppcap_extra") does the same as below.

write_csv(gdppcap_extra, "data/gdppcap_extra.csv")

To read the data, run the next code chunk. You do not have to run the code df_gdppcap_extra <- WDI(indicator = "NY.GDP.PCAP.KD", extra = TRUE) again.

gdppcap <- read_csv("data/gdppcap_extra.csv")

“data/gdpcap_extra.csv” is the way to express the name of the data gdpcap_extra.csv in csv format in the data folder.

3.6 country argument

If you want to import data for several countries, you can use iso2c codes of the countries.

ASEAN <- c("BN", "ID", "KH", "LA", "MM", "MY", "PH", "SG")
df_gdppcap_asean <- WDI(ASEAN, "NY.GDP.PCAP.KD")
df_gdppcap_asean %>% distinct(country) %>% pull()
[1] "Brunei Darussalam" "Indonesia"         "Cambodia"         
[4] "Lao PDR"           "Myanmar"           "Malaysia"         
[7] "Philippines"       "Singapore"        
wdi_cache$country %>% filter(iso2c %in% ASEAN) %>% distinct(country) %>% pull()
[1] "Brunei Darussalam" "Indonesia"         "Cambodia"         
[4] "Lao PDR"           "Myanmar"           "Malaysia"         
[7] "Philippines"       "Singapore"        

You can also use wdi_cache$country.

wdi_cache$country
wdi_cache$country %>% filter(iso2c %in% ASEAN) %>% pull(country)
[1] "Brunei Darussalam" "Indonesia"         "Cambodia"         
[4] "Lao PDR"           "Myanmar"           "Malaysia"         
[7] "Philippines"       "Singapore"        

You can find iso2c codes from the downloaded data, or using wdi_cache$country

wdi_cache$country %>% 
  filter(country %in% c("Brunei Darussalam", "Indonesia", "Cambodia", "Lao PDR", "Myanmar", "Malaysia", "Philippines", "Singapore")) %>%
  pull(iso2c)
[1] "BN" "ID" "KH" "LA" "MM" "MY" "PH" "SG"

You can also find countries in some category.

wdi_cache$country %>% 
  filter(region == "South Asia") %>%
  pull(country)
[1] "Afghanistan" "Bangladesh"  "Bhutan"      "India"       "Sri Lanka"  
[6] "Maldives"    "Nepal"       "Pakistan"   
wdi_cache$country %>% 
  filter(income == "Lower middle income") %>%
  pull(iso2c)
 [1] "AO" "BJ" "BD" "BO" "BT" "CI" "CM" "CG" "KM" "CV" "DJ" "DZ" "EG" "FM" "GH"
[16] "HN" "HT" "ID" "IN" "IR" "KE" "KG" "KH" "KI" "LA" "LB" "LK" "LS" "MA" "MM"
[31] "MN" "MR" "NG" "NI" "NP" "PK" "PH" "PG" "PS" "SN" "SB" "SV" "ST" "SZ" "TJ"
[46] "TL" "TN" "TZ" "UA" "UZ" "VN" "VU" "WS" "ZW"

The following shows a list of indicators

wdi_cache$series

The following is same as WDIsearch("gdp per cap", "name"). See WDIsearch help.

wdi_cache$series %>% filter(grepl("gdp per cap", name, ignore.case = TRUE))

4 Responses to Questions

4.1 Q1. How do we use histograms.

wdi_cache$series %>% filter(indicator == "SG.GEN.PARL.ZS") %>% pull(name)
[1] "Proportion of seats held by women in national parliaments (%)"
df_women_in_parl <- WDI(indicator = c(women_in_parl = "SG.GEN.PARL.ZS")) %>%
  drop_na(women_in_parl)
df_women_in_parl %>% filter(year == 2020) %>%
  ggplot(aes(women_in_parl)) + geom_histogram()

df_women_in_parl %>% filter(year == 2020) %>%
  ggplot(aes(women_in_parl)) + geom_histogram(binwidth = 5)

wdi_cache$series %>% filter(indicator == "IP.JRN.ARTC.SC") %>% pull(name)
[1] "Scientific and technical journal articles"
df_stja <- WDI(indicator = c(stja = "IP.JRN.ARTC.SC"), extra = TRUE) %>%
  drop_na(stja)

Default of the number of bins is 30. Change and find an appropriate one.

df_stja$year %>% summary()
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
   2000    2004    2009    2009    2014    2018 
df_stja %>% filter(income != "Aggregates") %>% 
  ggplot(aes(stja)) + geom_histogram(bins = 20)

df_stja %>% filter(income != "Aggregates", stja >0) %>% 
  ggplot(aes(stja)) + geom_histogram(bins = 20) + scale_x_log10()

df_stja %>% filter(income != "Aggregates", income != "Not classified", stja >0) %>% 
  ggplot(aes(stja, fill = income)) + geom_histogram(alpha = 0.7, bins = 20, color = "black") + scale_x_log10()

df_stja %>% filter(income != "Aggregates", income != "Not classified", stja >0) %>% 
  ggplot(aes(stja, fill = income)) + geom_density(alpha = 0.3) + scale_x_log10()

wdi_cache$series %>% filter(indicator == "MS.MIL.XPND.GD.ZS") %>% pull(name)
[1] "Military expenditure (% of GDP)"
df_milxpnd <- WDI(indicator = c(milxpnd = "MS.MIL.XPND.GD.ZS"), extra = TRUE) %>%
  drop_na(milxpnd)

Default of the number of bins is 30. Here I chose binwidth = 0.5 (%).

df_milxpnd %>% filter(income != "Aggregates", year == 2021) %>% 
  ggplot(aes(milxpnd, fill = income)) + geom_histogram(color = "black", binwidth = 0.5) + 
  labs(title = "Military expenditure (% of GDP)")

df_milxpnd %>% filter(income != "Aggregates", income != "Not classified", year == 2021) %>% 
  ggplot(aes(milxpnd, fill = income)) + geom_density(binwidth = 0.5, alpha = 0.3) + 
  labs(title = "Military expenditure (% of GDP)")
Warning: Ignoring unknown parameters: `binwidth`

4.2 Q2. Effect of unemployed rate under pandemic depending on income groups

wdi_cache$series %>% filter(indicator == "SL.UEM.TOTL.ZS") %>% pull(name)
[1] "Unemployment, total (% of total labor force) (modeled ILO estimate)"
df_ur <- WDI(indicator = c(ur = "SL.UEM.TOTL.ZS"), 
             extra = TRUE, cache = wdi_cache) %>% drop_na(ur)
df_ur %>% filter(income == "Aggregates") %>% filter(grepl('income', country)) %>% 
  filter(year >= 2018) %>% ggplot() + geom_line(aes(x = year, y = ur, color = country))

4.3 Q3. Add values at each data point.

wdi_cache$series %>% filter(indicator == "FP.CPI.TOTL.ZG") %>% pull(name)
[1] "Inflation, consumer prices (annual %)"
df_infl <- WDI(country = c("VN","CN","JP"), 
               indicator = c(inf = "FP.CPI.TOTL.ZG"), extra = TRUE) %>% drop_na(inf)
df_infl %>% filter(year %in% c(2000, 2007, 2020), 
                   country %in% c("Japan", "Vietnam", "China")) %>%
  ggplot(aes(x = year, y = inf, color= country)) + 
  geom_line() + geom_point() + 
  geom_text(aes(label = scales::label_percent(accuracy=1)(inf)), nudge_y = 0.8) + 
labs(title = "Inflation of Japan, Vietnam and China from 2000 to 2020", 
     x = "", y = "Inflation, consumer prices (annual %)")

5 Regression Lines; Topic of EDA5

wdi_cache$series %>% filter(indicator %in% c("SI.POV.NAHC","SI.POV.MDIM")) %>% pull(name)
[1] "Multidimensional poverty headcount ratio (% of total population)"   
[2] "Poverty headcount ratio at national poverty lines (% of population)"
df_wdi_poverty <- WDI(
  indicator = c(poverty = "SI.POV.NAHC", multipoverty = "SI.POV.MDIM", gdppercap = "NY.GDP.PCAP.KD"), start = 1990,
  extra = TRUE) %>% drop_na(poverty, multipoverty, gdppercap)
df_wdi_poverty %>%  
  group_by(country, year) %>%
  mutate(mean_gdp = mean(gdppercap)) %>%
  mutate(mean_poverty= mean(poverty)) %>%
  ungroup() %>% filter(income != "Aggregates") %>% 
  ggplot(aes(x = mean_gdp)) + geom_point(aes(y = mean_poverty, color = income)) +
  scale_x_log10() +  geom_smooth(aes(y = mean_poverty), formula = y~x, linetype="longdash", color = "black", method = "lm", se = FALSE) + 
  labs(x = "GDP per capita", y = "poverty rate (% of population)", title = "Poverty rates and GDP per capita", subtitle="world countries, 1990-2021 average, by income level")

df_wdi_poverty %>%  
  group_by(country, year) %>%
  mutate(mean_gdp = mean(gdppercap)) %>%
  mutate(mean_multipoverty= mean(multipoverty)) %>%
  ungroup() %>%
    filter(region !="Aggregates") %>% ggplot(aes(x = mean_gdp)) + geom_point(aes(y = mean_multipoverty, color = region)) +  
  scale_x_log10() +  
  geom_smooth(aes(y = mean_multipoverty), formula = y~x, linetype="longdash", color = "black", method = "lm", se = FALSE) + labs(x = "GDP per capita", y = "Multidimentinal poverty rate (% of population)", title = "Multidimentional Poverty rates and GDP per capita", subtitle="world countries, 1990-2021 average, by region")

6 Appendix: A secondary axis

  • Specify a secondary axis
    • This function is used in conjunction with a position scale to create a secondary axis, positioned opposite of the primary axis. All secondary axes must be based on a one-to-one transformation of the primary axes.

scale_y_continuous(sec.axis = sec_axis(~ . scaling_function))

6.1 Example

Suppose you have two indicators,

  • NY.GDP.MKTP.KD: GDP (constant 2015 US$)
  • NY.GDP.PCAP.KD: GDP per capita (constant 2015 US$)
WDIsearch(string = "NY.GDP.MKTP.KD", field = "indicator", short = FALSE, cache = wdi_cache)
WDIsearch(string = "NY.GDP.PCAP.KD", field = "indicator", short = FALSE, cache = wdi_cache)

List the name of countries of ASEAN and BRICs using wdi_cache$country.

asean <- c("Brunei Darussalam", "Cambodia", "Lao PDR", "Myanmar", 
           "Philippines", "Indonesia", "Malaysia", "Singapore")
brics <- c("Brazil", "Russian Federation", "India", "China")

Find the iso2c of the countries using wdi_cache$country.

wdi_cache$country %>% 
  filter(country %in% 
           c("Brunei Darussalam", "Cambodia", "Lao PDR", "Myanmar", 
           "Philippines", "Indonesia", "Malaysia", "Singapore",
           "Brazil", "Russian Federation", "India", "China")) %>% 
  pull(iso2c)
 [1] "BR" "BN" "CN" "ID" "IN" "KH" "LA" "MM" "MY" "PH" "RU" "SG"

Separate the iso3c’s of the countries with commas and read data using WDI.

wdi_gdp <- WDI(
  country = c("BR", "BN", "CN", "ID", "IN", "KH", "LA", "MM", "MY", "PH", "RU", "SG"),
  indicator = c(gdp = "NY.GDP.MKTP.KD", gdpPercap = "NY.GDP.PCAP.KD"),
  start = 1960, extra = TRUE, cache = wdi_cache)
wdi_gdp %>% filter(country %in% asean) %>% drop_na(gdp, gdpPercap) %>% summary() 
   country             iso2c              iso3c                year     
 Length:424         Length:424         Length:424         Min.   :1960  
 Class :character   Class :character   Class :character   1st Qu.:1980  
 Mode  :character   Mode  :character   Mode  :character   Median :1995  
                                                          Mean   :1994  
                                                          3rd Qu.:2008  
                                                          Max.   :2021  
    status          lastupdated             gdp              gdpPercap      
 Length:424         Length:424         Min.   :2.109e+09   Min.   :  144.0  
 Class :character   Class :character   1st Qu.:1.069e+10   1st Qu.:  978.2  
 Mode  :character   Mode  :character   Median :4.099e+10   Median : 1891.2  
                                       Mean   :1.149e+11   Mean   : 9718.5  
                                       3rd Qu.:1.430e+11   3rd Qu.: 8777.6  
                                       Max.   :1.066e+12   Max.   :66176.4  
    region            capital           longitude           latitude        
 Length:424         Length:424         Length:424         Length:424        
 Class :character   Class :character   Class :character   Class :character  
 Mode  :character   Mode  :character   Mode  :character   Mode  :character  
                                                                            
                                                                            
                                                                            
    income            lending         
 Length:424         Length:424        
 Class :character   Class :character  
 Mode  :character   Mode  :character  
                                      
                                      
                                      

Using the summary, decide the scaling of two variables, gdpPercap and gdp.

wdi_gdp %>% drop_na(gdp, gdpPercap) %>%
  filter(country %in% asean) %>%
  ggplot() + 
  geom_line(aes(x = year, y = gdpPercap, linetype = country)) + 
  geom_line(aes(x = year, y = gdp/(10^7), col = country)) + 
  coord_trans(x ="identity", y="log10") +
  scale_y_continuous(sec.axis = sec_axis(~ . *(10^7), name = "gdp/(10^7)"))

6.1.1 BRICs

wdi_gdp %>% filter(country %in% brics) %>% drop_na(gdp, gdpPercap) %>% summary() 
   country             iso2c              iso3c                year     
 Length:219         Length:219         Length:219         Min.   :1960  
 Class :character   Class :character   Class :character   1st Qu.:1978  
 Mode  :character   Mode  :character   Mode  :character   Median :1994  
                                                          Mean   :1993  
                                                          3rd Qu.:2008  
                                                          Max.   :2021  
    status          lastupdated             gdp              gdpPercap      
 Length:219         Length:219         Min.   :1.091e+11   Min.   :  163.9  
 Class :character   Class :character   1st Qu.:3.564e+11   1st Qu.:  531.7  
 Mode  :character   Mode  :character   Median :9.215e+11   Median : 2758.9  
                                       Mean   :1.644e+12   Mean   : 3825.8  
                                       3rd Qu.:1.500e+12   3rd Qu.: 6579.5  
                                       Max.   :1.580e+13   Max.   :11188.3  
    region            capital           longitude           latitude        
 Length:219         Length:219         Length:219         Length:219        
 Class :character   Class :character   Class :character   Class :character  
 Mode  :character   Mode  :character   Mode  :character   Mode  :character  
                                                                            
                                                                            
                                                                            
    income            lending         
 Length:219         Length:219        
 Class :character   Class :character  
 Mode  :character   Mode  :character  
                                      
                                      
                                      

Using the summary, decide the scaling of two variables, gdpPercap and gdp.

wdi_gdp %>% drop_na(gdp, gdpPercap) %>%
  filter(country %in% brics) %>%
  ggplot() + 
  geom_line(aes(x = year, y = gdpPercap, linetype = country)) + 
  geom_line(aes(x = year, y = gdp/(10^9), col = country)) + 
  coord_trans(x ="identity", y="log10") +
  scale_y_continuous(sec.axis = sec_axis(~ . *(10^7), name = "gdp/(10^9)"))

LS0tCnRpdGxlOiAiUmVzcG9uc2VzIHRvIEFzc2lnbm1lbnQgMyIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OiB5ZXMKICAgIGhpZ2hsaWdodDogaGFkZG9jawogICAgdGhlbWU6IGNvc21vCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcwogIHBkZl9kb2N1bWVudDoKICAgIHRvYzogeWVzCi0tLQoKIyMgQXNzaWdubWVudCBUaHJlZTogVGhlIFdlZWsgRm91ciBBc3NpZ25tZW50IHstfQoKKipXREkgYW5kIGBnZ3Bsb3QyYCoqCgoqIENyZWF0ZSBhbiBSIE5vdGVib29rIG9mIGEgRGF0YSBBbmFseXNpcyBjb250YWluaW5nIHRoZSBmb2xsb3dpbmcgYW5kIHN1Ym1pdCB0aGUgcmVuZGVyZWQgSFRNTCBmaWxlIChlZy4gYGEzXzEyMzQ1Ni5uYi5odG1sYCAgYnkgcmVwbGFjaW5nIDEyMzQ1NiB3aXRoIHlvdXIgSUQpCiAgMS4gY3JlYXRlIGFuIFIgTm90ZWJvb2sgdXNpbmcgdGhlIFIgTm90ZWJvb2sgVGVtcGxhdGUgaW4gTW9vZGxlLCAgc2F2ZSBhcyBgYTNfMTIzNDU2LlJtZGAsIAogIDIuIHdyaXRlIHlvdXIgbmFtZSBhbmQgSUQgYW5kIHRoZSBjb250ZW50cywgCiAgMy4gcnVuIGVhY2ggY29kZSBibG9jaywgCiAgNC4gcHJldmlldyB0byBjcmVhdGUgYGEzXzEyMzQ1Ni5uYi5odG1sYCwKICA1LiBzdWJtaXQgIGBhM18xMjM0NTYubmIuaHRtbGAgdG8gTW9vZGxlLgoKMS4gQ2hvb3NlIGF0IGxlYXN0IG9uZSBpbmRpY2F0b3Igb2YgV0RJCgogICAgLSBJbmZvcm1hdGlvbiBvZiB0aGUgZGF0YTogTmFtZSwgSW5kaWNhdG9yLCBEZXNjcmlwdGlvbiwgU291cmNlLCBldGMuCiAgICAtIERvd25sb2FkIHRoZSBkYXRhIHdpdGggYFdESWAKICAgIC0gRXhwbGFpbiB3aHkgeW91IGNob3NlIHRoZSBpbmRpY2F0b3IKICAgIC0gTGlzdCBxdWVzdGlvbnMgeW91IHdhbnQgdG8gc3R1ZHkKCjIuIEV4cGxvcmUgdGhlIGRhdGEgdXNpbmcgdmlzdWFsaXphdGlvbiB1c2luZyBgZ2dwbG90MmAKCiAgICAtIFVzZSBhIGhpc3RvZ3JhbSAoZ2VvbV9oaXN0b2dyYW0pLCBib3hwbG90IChnZW9tX2JveHBsb3QpLCBhIHNjYXR0ZXIgcGxvdCAoZ2VvbV9wb2ludCksIGEgbGluZSBwbG90IChnZW9tX2xpbmUpCiAgICAtIEZvciBhdCBsZWFzdCBvbmUgY2hhcnQsIGFkZCB0aXRsZSwgYW5kIGxhYmVscyBvZiBheGlzLCBhbmQgYWRkIGFuIGV4cGxhbmF0aW9uIG9mIGl0CgozLiBPYnNlcnZhdGlvbnMgYW5kIGRpZmZpY3VsdGllcyBlbmNvdW50ZXJlZC4KCioqRHVlOioqIDIwMjMtMDEtMTYgMjM6NTk6MDAuIFN1Ym1pdCB5b3VyIFIgTm90ZWJvb2sgZmlsZSBpbiBNb29kbGUgKFRoZSBUaGlyZCBBc3NpZ25tZW50KS4gRHVlIG9uIE1vbmRheSEKCiMgU2V0IHVwCgpGb2xsb3cgdGh3IHdvcmtmbG93IGV4cGxhaW5lZCBpbiBFREE0IG9uIEphbnVhcnkgMTguCgojIyBFREEgYnkgUiBTdHVkaW86IFN0ZXAgMQoKSW4gUlN0dWRpbywKCjEuMS4gUHJvamVjdAoKICAqIENyZWF0ZSBhIG5ldyBwcm9qZWN0OiBGaWxlID4gTmV3IFByb2plY3Q7IG9yICAKICAqIE9wZW4gYSBwcm9qZWN0OiBGaWxlID4gT3BlbiBQcm9qZWN0LCBPcGVuIFByb2plY3QgaW4gTmV3IFNlc3Npb24sIE9wZW4gUmVjZW50IFByb2plY3QgIAogICAgLSBJdCBpcyBlYXNpZXIgdG8gZmluZCBhbiBleGlzdGluZyBwcm9qZWN0IGZyb206IEZpbGUgPiBSZWNlbnQgUHJvamVjdCAKICAqIF9DaGVjayB0aGVyZSBpcyBhIGZpbGUgYHByb2plY3RfbmFtZS5ScHJvamAgaW4geW91ciBwcm9qZWN0IGZvbGRlciAoZGlyZWN0b3J5KV8KCiAKMS4yLiBkYXRhIGZvbGRlciAoZGlyZWN0b3J5KSBgZGF0YWAKCiAgKiBDcmVhdGUgYSBkYXRhIGZvbGRlcjogUHJlc3MgTmV3IEZvbGRlciBhdCB0aGUgcmlnaHQgYm90dG9tIHBhbmU7IG9yIAogICogQ29uZmlybSB0aGUgZGF0YSBmb2xkZXIgcHJldmlvdXNseSBjcmVhdGVkOiBQcmVzcyBGaWxlcyBhdCB0aGUgcmlnaHQgYm90dG9tIHBhbmUKICAqIF9JZiB5b3UgZm9sbG93IDEsIHRoZSBkYXRhIGZvbGRlciBleGlzdHMgaW4geW91ciBwcm9qZWN0IGZvbGRlcl8KCiAKMS4zLiBNb3ZlIChvciBjb3B5KSBkYXRhIGZvciB0aGUgcHJvamVjdCB0byB0aGUgZGF0YSBmb2xkZXIKCiAgKiBJZiB5b3UgZG93bmxvYWRlZCB0aGUgZGF0YSwgaXQgaXMgaW4geW91ciBEb3dubG9hZCBmb2xkZXIuIE1vdmUgaXQgdG8gYGRhdGFgLgogICogX0NoZWNrIGluIHlvdXIgUlN0dWRpbyB0aGF0IHlvdXIgZGF0YSBpcyBpbiBgZGF0YWA6IFByZXNzIEZpbGVzIGF0IHRoZSByaWdodCBib3R0b20gcGFuZSBhbmQgY2xpY2sgYGRhdGFgLCB0aGUgZGF0YSBmb2xkZXIuXwoKCiMjIEVEQSBieSBSIFN0dWRpbzogU3RlcCAyCgoyLjEuIFByb2plY3QgTm90ZWJvb2s6IE1lbW8KCiAgLSBDcmVhdGUgYW4gUiBOb3RlYm9vazogRmlsZSA+IE5ldyBGaWxlID4gUiBOb3RlYm9vawogIAogICAgKyBZb3UgY2FuIHVzZSBSIE5vdGVib29rIHRlbXBsYXRlIGluIE1vb2RsZSBieSBtb3ZpbmcgdGhlIHRlbXBsYXRlICh0ZW1wbGF0ZS5SbWQgb3IgdGVtcGxhdGUubmIuUm1kKSBmaWxlIGluIHlvdXIgcHJvamVjdCBmb2xkZXIgb3IgY29weSBhbmQgcGFzdGUgdGhlIHRleHQgZmlsZSBpbnRvIHlvdXIgbmV3IFIgTm90ZWJvb2suCiAgICArIElmIHlvdSB1c2UgdGVtcGxhdGUubmIuUm1kIChSIE5vdGVib29rIEZpbGUpLCBjaG9vc2UgT3BlbiBpbiBFZGl0b3IuCiAgICAKICAtIEFkZCBkZXNjcmlwdGl2ZSB0aXRsZS4gCiAgCjIuMi4gU2V0dXAgQ29kZSBDaHVuayAKCiAgLSBDcmVhdGUgYSBjb2RlIGNodW5rIGFuZCBhZGQgcGFja2FnZXMgdG8gdXNlIGluIHRoZSBwcm9qZWN0IGFuZCBSVU4gdGhlIGNvZGUuCiAgCiAgICAgICsgbGlicmFyeSh0aWR5dmVyc2UpCiAgICAgICsgbGlicmFyeShXREkpCiAgICAgICsgb3IgYW55IG90aGVyIHBhY2thZ2VzCiAgICAgIApgYGB7cn0KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoV0RJKQpgYGAKCl9XaGVuIHBlb3BsZSByZWFkIGEgcGFwZXIsIHRoZXkgd2FudCB0byBrbm93IHRoZSBtaW5pbWFsIHNldCBvZiBwYWNrYWdlcyByZXF1aXJlZCB0byBpbnN0YWxsLiBTbyBpdCBpcyBiZXR0ZXIgdG8gbG9hZCB0aGUgcGFja2FnZXMgYnkgbGlicmFyeSgpIHlvdSBhY3R1YWxseSBuZWVkIGluIHRoZSBwYXBlci5fCgoyLjMuIENob29zZSBgU291cmNlYCBvciBgVmlzdWFsYCBlZGl0b3IgbW9kZSwgYW5kIHN0YXJ0IGVkaXRpbmcgUHJvamVjdCBOb3RlYm9vawoKICAtIFNldCB1cCBIZWFkaW5ncyBzdWNoIGFzOiBBYm91dCwgRGF0YSwgQW5hbHlzaXMgYW5kIFZpc3VhbGl6YXRpb25zLCBDb25jbHVzaW9ucwogIC0gVW5kZXIgQWJvdXQgb3IgRGF0YSwgcGFzdGUgdXJsIG9mIHRoZSBzaXRlcyBhbmQvb3IgdGhlIGRhdGEKCjIuNC4gRWRpdCBhIG5ldyBmaWxlIGJ5IHNhdmluZyBhcyBmb3IgYSByZXBvcnQKCiAgLSBGaWxlID4gU2F2ZSBBcy4uLgoKIyBHZW5lcmFsIENvbW1lbnRzCgojIyBWYXJpYmxlcwoKV2Ugc2hvdWxkIGtub3cgZmlyc3QgYWJvdXQgdGhlIHZhcmlhYmxlcy4gQXQgbGVhc3QgeW91IG11c3Qga25vdyBpZiBlYWNoIG9mIHRoZSB2YXJpYWJsZXMgaXMgYSBjYXRlZ29yaWNhbCB2YXJpYWJsZSBvciBhIG51bWVyaWNhbCB2YXJpYWJsZS4KCiMjIFZpc3VhbGl6YXRpb24KCiAgKiBXaGF0IHR5cGUgb2YgdmFyaWF0aW9uIG9jY3VycyB3aXRoaW4gbXkgdmFyaWFibGVzPwogICogV2hhdCB0eXBlIG9mIGNvdmFyaWF0aW9uIG9jY3VycyBiZXR3ZWVuIG15IHZhcmlhYmxlcz8KCiMgV29ybGQgRGV2ZWxvcG1lbnQgSW5kaWNhdG9ycyAoV0RJKQoKIyMgU2V0dXAKCkl0IGlzIG5vdCBhIG11c3QsIGJ1dCBpdCBpcyBnb29kIHRvIHJ1biB0aGUgZm9sbG93aW5nIGNvZGUgY2h1bmsgYW5kIHVzZSBgd2RpX2NhY2hlYCBmb3IgYFdESXNlYXJjaCgpYCB0byB1cGRhdGUgdGhlIG1hdGEgZGF0YS4gU2VlIGBXREljYWNoZWAgaGVscC4gCgpgYGB7ciBjYWNoZSA9IFRSVUV9CndkaV9jYWNoZSA8LSBXREljYWNoZSgpCmBgYAoKCiMjIEluZGljYXRvcnMgVXNlZCBpbiBBc3NpZ25tZW50IFRocmVlCgoqIE5ZLkdEUC5QQ0FQLktEOiBHRFAgcGVyIGNhcGl0YSAoY29uc3RhbnQgMjAxNSBVUyQpCiogTlkuR0RQLk1LVFAuQ0Q6IEdEUCAoY3VycmVudCBVUyQpCiogTlkuR0RQLlBDQVAuS0QuWkc6IEdEUCBwZXIgY2FwaXRhIGdyb3d0aCAoYW5udWFsJSkKKiBTUC5QT1AuVE9UTDogVG90YWwgUG9wdWxhdGlvbgoqIElQLkpSTi5BUlRDLlNDOiBTY2llbnRpZmljIGFuZCB0ZWNobmljYWwgam91cm5hbCBhcnRpY2xlcwoqIEZQLkNQSS5UT1RMLlpHOiBJbmZsYXRpb24sIGNvbnN1bWVyIHByaWNlcyAoJSBhbm51YWwgZ3Jvd3RoKSAKKiBEVC5PREEuT0RBVC5QQy5aUzogTmV0IE9EQSByZWNlaXZlZCBwZXIgY2FwaXRhIChjdXJyZW50IFVTJCkKKiBCWC5LTFQuRElOVi5DRC5XRDogRm9yZWlnbiBkaXJlY3QgaW52ZXN0bWVudCwgbmV0IGluZmxvd3MgKEJvUCwgY3VycmVudCBVUyQpCiogTVMuTUlMLlhQTkQuR0QuWlM6IE1pbGl0YXJ5IGV4cGVuZGl0dXJlICglIG9mIEdEUCkKKiBNUy5NSUwuVE9UTC5QMTogVG90YWwgQXJtZWQgRm9yY2VzIFBlcnNvbm5lbAoqIFNJLlBPVi5NRElNOiBNdWx0aWRpbWVuc2lvbmFsIHBvdmVydHkgaGVhZGNvdW50IHJhdGlvICglIG9mIHRvdGFsIHBvcHVsYXRpb24pCiogU0kuUE9WLk5BSEM6IFBvdmVydHkgaGVhZGNvdW50IHJhdGlvIGF0IG5hdGlvbmFsIHBvdmVydHkgbGluZXMgKCUgb2YgcG9wdWxhdGlvbikgCiogU0kuUE9WLkdJTkk6IEdpbmkgaW5kZXgKKiBOWS5HTlMuSUNUUi5aUzogR3Jvc3Mgc2F2aW5ncyAoJSBvZiBHRFApCiogU0wuVUVNLlRPVEwuWlM6IFVuZW1wbG95bWVudCwgdG90YWwgKCUgb2YgdG90YWwgbGFib3IgZm9yY2UpIChtb2RlbGVkIElMTyBlc3RpbWF0ZSkKKiBTUC5VUkIuVE9UTC5JTi5aUyAoVXJiYW4gcG9wdWxhdGlvbiAoJSBvZiB0b3RhbCBwb3B1bGF0aW9uKSkKKiBBRy5MTkQuQUdSSS5aUzogQWdyaWN1bHR1cmFsIGxhbmQgKCUgb2YgbGFuZCBhcmVhKQoqIFNFLkFEVC5MSVRSLkZFLlpTOiBMaXRlcmFjeSByYXRlLCBhZHVsdCBmZW1hbGUgKCUgb2YgZmVtYWxlcyBhZ2VzIDE1IGFuZCBhYm92ZSkpCiogU0UuQURULkxJVFIuTUEuWlM6IExpdGVyYWN5IHJhdGUsIGFkdWx0IG1hbGUgKCUgb2YgbWFsZXMgYWdlcyAxNSBhbmQgYWJvdmUpKSAKKiBTRS5BRFQuTElUUi5aUzogTGl0ZXJhY3kgcmF0ZSwgYWR1bHQgdG90YWwKKiBTRS5BRFQuMTUyNC5MVC5GRS5aUzogTGl0ZXJhY3kgcmF0ZSwgeW91dGggZmVtYWxlICglIG9mIGZlbWFsZXMgYWdlcyAxNS0yNCkKKiBTRS5YUEQuVE9UTC5HRC5aUzogR292ZXJubWVudCBleHBlbmRpdHVyZSBvbiBlZHVjYXRpb24sIHRvdGFsICglIG9mIEdEUCkKKiBTRy5HRU4uUEFSTC5aUzogUHJvcG9ydGlvbiBvZiBzZWF0cyBoZWxkIGJ5IHdvbWVuIGluIG5hdGlvbmFsIHBhcmxpYW1lbnRzICglKQoKIyMgV0RJc2VhcmNoCgpXZSBvYnRhaW4gdGhlIGluZm9ybWF0aW9uIG9mIHRoZSBkYXRhLCBpLmUuLCBtZXRhIGRhdGEgb2YgV0RJOiBOYW1lLCBJbmRpY2F0b3IsIERlc2NyaXB0aW9uLCBTb3VyY2UsIGV0Yy4gYnkgYFdESXNlYXJjaGAuCgoqIFVzYWdlCgpgYGAKV0RJc2VhcmNoKHN0cmluZyA9ICJnZHAiLCBmaWVsZCA9ICJuYW1lIiwgc2hvcnQgPSBUUlVFLCBjYWNoZSA9IE5VTEwpCmBgYAoKKiBBcmd1bWVudHMKCiAgKiBgc3RyaW5nYDogQ2hhcmFjdGVyIHN0cmluZy4gU2VhcmNoIGZvciB0aGlzIHN0cmluZyB1c2luZyBncmVwIHdpdGggaWdub3JlLmNhc2U9VFJVRS4KCiAgKiBgZmllbGRgOiBDaGFyYWN0ZXIgc3RyaW5nLiBTZWFyY2ggdGhpcyBmaWVsZC4gQWRtaXNzaWJsZSBmaWVsZHM6ICdpbmRpY2F0b3InLCAnbmFtZScsICdkZXNjcmlwdGlvbicsICdzb3VyY2VEYXRhYmFzZScsICdzb3VyY2VPcmdhbml6YXRpb24nCgogICogYHNob3J0YDogVFJVRTogUmV0dXJucyBvbmx5IHRoZSBpbmRpY2F0b3IncyBjb2RlIGFuZCBuYW1lLiBGQUxTRTogUmV0dXJucyB0aGUgaW5kaWNhdG9yJ3MgY29kZSwgbmFtZSwgZGVzY3JpcHRpb24sIGFuZCBzb3VyY2UuCgogICogYGNhY2hlYDogRGF0YSBsaXN0IGdlbmVyYXRlZCBieSB0aGUgV0RJY2FjaGUgZnVuY3Rpb24uIElmIG9taXR0ZWQsIFdESXNlYXJjaCB3aWxsIHNlYXJjaCBhIGxvY2FsIGxpc3Qgb2Ygc2VyaWVzLgoKSWYgeW91IGZvbGxvdyB0aGUgb3JkZXIgb2YgdGhlIGFyZ3VtZW50cywgeW91IGNhbiBvbWl0IGFyZ3VtZW50IG5hbWVzOiBgc3RyaW5nYCwgYGZpZWxkYCwgYHNob3J0YCwgYGNhY2hlYC4KCiogVGhlIHNpbXBsZXN0IGZvcm1hdCAxLgoKYGBge3J9CldESXNlYXJjaCgiTlkuR05TLklDVFIuWlMiLCAiaW5kaWNhdG9yIikKYGBgCiogVGhlIHNpbXBsZXN0IGZvcm1hdCAyLgoKYGBge3J9CldESXNlYXJjaCgiTGl0ZXJhY3kgcmF0ZSIsICJuYW1lIikKYGBgCgoqIERldGFpbGVkIHdpdGggc2hvcnQgPSBGQUxTRQoKYGBge3J9CldESXNlYXJjaCgiSVAuSlJOLkFSVEMuU0MiLCAiaW5kaWNhdG9yIiwgRkFMU0UpCmBgYAoqIFlvdSBjYW4gdXNlIGB3ZGlfY2FjaGVgIGRvd25sb2FkZWQgYWJvdmUgdG8gdXNlIHRoZSB1cGRhdGVkIG1ldGEgZGF0YS4KCmBgYHtyfQpXRElzZWFyY2goIkdvdmVybm1lbnQgZXhwZW5kaXR1cmUgb24gZWR1Y2F0aW9uIiwgIm5hbWUiLCBGQUxTRSwgd2RpX2NhY2hlKQpgYGAKCgojIyBJbXBvcnRpbmcgRGF0YSBVc2luZyBXREkKCiogVGhlIHNob3J0ZXN0IGZvcm0uIFRoZSBmb2xsb3dpbmcgaXMgc2FtZSBhczoKYFdESShjb3VudHJ5ID0gImFsbCIsIGluZGljYXRvciA9ICJOWS5HRFAuUENBUC5LRCIsIHN0YXJ0ID0gMTk2MCwgZW5kID0gTlVMTCwgZXh0cmEgPSBGQUxTRSwgY2FjaGUgPSBOVUxMLCBsYXRlc3QgPSBOVUxMLCBsYW5ndWFnZSA9ICJlbilgCgpgYGB7cn0KV0RJKGluZGljYXRvciA9ICJOWS5HRFAuUENBUC5LRCIpCmBgYAoKKiBJbiBvcmRlciB0byB1c2UgdGhlIGRvd25sb2FkZWQgZGF0YSwgd2UgbmVlZCB0byBhc3NpZ24gYSBuYW1lIHRvIGl0LiBJdCBjYW4gYmUgYGRmYCBpZiB5b3UgZG93bmxvYWQgYW5kIHVzZSBvbmx5IG9uZSBkYXRhLCBidXQgaXQgaXMgYmV0dGVyIHRvIGFzc2lnbiB0aGUgZGF0YSB0byBiZSBhIG1vcmUgZGVzY3JpcHRpdmUgbmFtZS4KCmBgYHtyfQpkZl9nZHBwY2FwIDwtIFdESShpbmRpY2F0b3IgPSAiTlkuR0RQLlBDQVAuS0QiKQpkZl9nZHBwY2FwCmBgYAoKKiBJZiB5b3Ugd2FudCB0byB1c2UgZXh0cmEgaW5mb3JtYXRpb24gc3VjaCBhcyBgcmVnaW9uYCwgYGluY29tZWAsIGBsZW5kaW5nYCwgdXNlIGBleHRyYSA9IFRSVUVgLgoKYGBge3J9CmRmX2dkcHBjYXBfZXh0cmEgPC0gV0RJKGluZGljYXRvciA9ICJOWS5HRFAuUENBUC5LRCIsIGV4dHJhID0gVFJVRSkKZGZfZ2RwcGNhcF9leHRyYQpgYGAKCiMjIFdyaXRpbmcgYW5kIHJlYWRpbmcgYSBjc3YgZmlsZQoKU2luY2UgdGhlIGRhdGEgaXMgZ2VuZXJhbGx5IGh1Z2UsIGl0IGlzIGJldHRlciB0byB1c2UgYSBkYXRhIHNhdmVkIGluIHlvdXIgY29tcHV0ZXIuCkJlZm9yZSBzYXZpbmcgaXQgY2hlY2sgd2hldGhlciB5b3UgaGF2ZSBgZGF0YWAgZm9sZGVyIChvciBkaXJlY3RvcnkpIGluIHlvdSBwcm9qZWN0IGZvbGRlci4gVXNlIHRoZSBgRmlsZXNgIHRhYiBvZiB0aGUgcmlnaHQgYm90dG9tIHBhbmUuIFlvdSBzaG91bGQgYmUgYWJsZSB0byBzZWUgdGhlIHByb2plY3QgaWNvbiB3aXRoIFJwcm9qIGF0IHRoZSBlbmQsIHlvdXIgUiBOb3RlYm9vayBmaWxlIHlvdSBhcmUgZWRpdGluZywgYW5kIHRoZSBgZGF0YWAgZm9sZGVyLiBTaW5jZSBgLmNzdmAgaXMgYXV0b21hdGljYWxseSBhZGRlZCwgYHdyaXRlX2NzdihnZHBwY2FwX2V4dHJhLCAiZGF0YS9nZHBwY2FwX2V4dHJhIilgIGRvZXMgdGhlIHNhbWUgYXMgYmVsb3cuCgpgYGB7ciBldmFsID0gRkFMU0V9CndyaXRlX2NzdihnZHBwY2FwX2V4dHJhLCAiZGF0YS9nZHBwY2FwX2V4dHJhLmNzdiIpCmBgYAoKVG8gcmVhZCB0aGUgZGF0YSwgcnVuIHRoZSBuZXh0IGNvZGUgY2h1bmsuIFlvdSBkbyBub3QgaGF2ZSB0byBydW4gdGhlIGNvZGUgYGRmX2dkcHBjYXBfZXh0cmEgPC0gV0RJKGluZGljYXRvciA9ICJOWS5HRFAuUENBUC5LRCIsIGV4dHJhID0gVFJVRSlgIGFnYWluLgoKYGBge3IgZXZhbCA9IEZBTFNFfQpnZHBwY2FwIDwtIHJlYWRfY3N2KCJkYXRhL2dkcHBjYXBfZXh0cmEuY3N2IikKYGBgCgoiZGF0YS9nZHBjYXBfZXh0cmEuY3N2IiBpcyB0aGUgd2F5IHRvIGV4cHJlc3MgdGhlIG5hbWUgb2YgdGhlIGRhdGEgYGdkcGNhcF9leHRyYS5jc3ZgIGluIGNzdiBmb3JtYXQgaW4gdGhlIGRhdGEgZm9sZGVyLiAKCiMjIGBjb3VudHJ5YCBhcmd1bWVudAoKSWYgeW91IHdhbnQgdG8gaW1wb3J0IGRhdGEgZm9yIHNldmVyYWwgY291bnRyaWVzLCB5b3UgY2FuIHVzZSBgaXNvMmNgIGNvZGVzIG9mIHRoZSBjb3VudHJpZXMuCgpgYGB7cn0KQVNFQU4gPC0gYygiQk4iLCAiSUQiLCAiS0giLCAiTEEiLCAiTU0iLCAiTVkiLCAiUEgiLCAiU0ciKQpkZl9nZHBwY2FwX2FzZWFuIDwtIFdESShBU0VBTiwgIk5ZLkdEUC5QQ0FQLktEIikKZGZfZ2RwcGNhcF9hc2VhbiAlPiUgZGlzdGluY3QoY291bnRyeSkgJT4lIHB1bGwoKQpgYGAKCgpgYGB7cn0Kd2RpX2NhY2hlJGNvdW50cnkgJT4lIGZpbHRlcihpc28yYyAlaW4lIEFTRUFOKSAlPiUgZGlzdGluY3QoY291bnRyeSkgJT4lIHB1bGwoKQpgYGAKCgpZb3UgY2FuIGFsc28gdXNlIGB3ZGlfY2FjaGUkY291bnRyeWAuCgpgYGB7cn0Kd2RpX2NhY2hlJGNvdW50cnkKYGBgCgpgYGB7cn0Kd2RpX2NhY2hlJGNvdW50cnkgJT4lIGZpbHRlcihpc28yYyAlaW4lIEFTRUFOKSAlPiUgcHVsbChjb3VudHJ5KQpgYGAKCgpZb3UgY2FuIGZpbmQgaXNvMmMgY29kZXMgZnJvbSB0aGUgZG93bmxvYWRlZCBkYXRhLCBvciB1c2luZyB3ZGlfY2FjaGUkY291bnRyeQoKYGBge3J9CndkaV9jYWNoZSRjb3VudHJ5ICU+JSAKICBmaWx0ZXIoY291bnRyeSAlaW4lIGMoIkJydW5laSBEYXJ1c3NhbGFtIiwgIkluZG9uZXNpYSIsICJDYW1ib2RpYSIsICJMYW8gUERSIiwgIk15YW5tYXIiLCAiTWFsYXlzaWEiLCAiUGhpbGlwcGluZXMiLCAiU2luZ2Fwb3JlIikpICU+JQogIHB1bGwoaXNvMmMpCmBgYAoKWW91IGNhbiBhbHNvIGZpbmQgY291bnRyaWVzIGluIHNvbWUgY2F0ZWdvcnkuCgpgYGB7cn0Kd2RpX2NhY2hlJGNvdW50cnkgJT4lIAogIGZpbHRlcihyZWdpb24gPT0gIlNvdXRoIEFzaWEiKSAlPiUKICBwdWxsKGNvdW50cnkpCmBgYAoKCmBgYHtyfQp3ZGlfY2FjaGUkY291bnRyeSAlPiUgCiAgZmlsdGVyKGluY29tZSA9PSAiTG93ZXIgbWlkZGxlIGluY29tZSIpICU+JQogIHB1bGwoaXNvMmMpCmBgYAoKVGhlIGZvbGxvd2luZyBzaG93cyBhIGxpc3Qgb2YgaW5kaWNhdG9ycwoKYGBge3J9CndkaV9jYWNoZSRzZXJpZXMKYGBgCgpUaGUgZm9sbG93aW5nIGlzIHNhbWUgYXMgYFdESXNlYXJjaCgiZ2RwIHBlciBjYXAiLCAibmFtZSIpYC4gU2VlIFdESXNlYXJjaCBoZWxwLgoKYGBge3J9CndkaV9jYWNoZSRzZXJpZXMgJT4lIGZpbHRlcihncmVwbCgiZ2RwIHBlciBjYXAiLCBuYW1lLCBpZ25vcmUuY2FzZSA9IFRSVUUpKQpgYGAKCiMgUmVzcG9uc2VzIHRvIFF1ZXN0aW9ucwoKIyMgUTEuIEhvdyBkbyB3ZSB1c2UgaGlzdG9ncmFtcy4KCiogW0hpc3RvZ3JhbXMgYW5kIGZyZXF1ZW5jeSBwb2x5Z29uc10oaHR0cHM6Ly9nZ3Bsb3QyLnRpZHl2ZXJzZS5vcmcvcmVmZXJlbmNlL2dlb21faGlzdG9ncmFtLmh0bWwpCiogW1Bvc2l0IENsb3VkOiBIaXN0b2dyYW1zXShodHRwczovL3Bvc2l0LmNsb3VkL2xlYXJuL3ByaW1lcnMvMy4zKQoKCmBgYHtyfQp3ZGlfY2FjaGUkc2VyaWVzICU+JSBmaWx0ZXIoaW5kaWNhdG9yID09ICJTRy5HRU4uUEFSTC5aUyIpICU+JSBwdWxsKG5hbWUpCmRmX3dvbWVuX2luX3BhcmwgPC0gV0RJKGluZGljYXRvciA9IGMod29tZW5faW5fcGFybCA9ICJTRy5HRU4uUEFSTC5aUyIpKSAlPiUKICBkcm9wX25hKHdvbWVuX2luX3BhcmwpCmBgYAoKYGBge3J9CmRmX3dvbWVuX2luX3BhcmwgJT4lIGZpbHRlcih5ZWFyID09IDIwMjApICU+JQogIGdncGxvdChhZXMod29tZW5faW5fcGFybCkpICsgZ2VvbV9oaXN0b2dyYW0oKQpgYGAKCmBgYHtyfQpkZl93b21lbl9pbl9wYXJsICU+JSBmaWx0ZXIoeWVhciA9PSAyMDIwKSAlPiUKICBnZ3Bsb3QoYWVzKHdvbWVuX2luX3BhcmwpKSArIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gNSkKYGBgCgpgYGB7cn0Kd2RpX2NhY2hlJHNlcmllcyAlPiUgZmlsdGVyKGluZGljYXRvciA9PSAiSVAuSlJOLkFSVEMuU0MiKSAlPiUgcHVsbChuYW1lKQpkZl9zdGphIDwtIFdESShpbmRpY2F0b3IgPSBjKHN0amEgPSAiSVAuSlJOLkFSVEMuU0MiKSwgZXh0cmEgPSBUUlVFKSAlPiUKICBkcm9wX25hKHN0amEpCmBgYAoKRGVmYXVsdCBvZiB0aGUgbnVtYmVyIG9mIGJpbnMgaXMgMzAuIENoYW5nZSBhbmQgZmluZCBhbiBhcHByb3ByaWF0ZSBvbmUuCgpgYGB7cn0KZGZfc3RqYSR5ZWFyICU+JSBzdW1tYXJ5KCkKYGBgCgoKYGBge3J9CmRmX3N0amEgJT4lIGZpbHRlcihpbmNvbWUgIT0gIkFnZ3JlZ2F0ZXMiKSAlPiUgCiAgZ2dwbG90KGFlcyhzdGphKSkgKyBnZW9tX2hpc3RvZ3JhbShiaW5zID0gMjApCmBgYApgYGB7cn0KZGZfc3RqYSAlPiUgZmlsdGVyKGluY29tZSAhPSAiQWdncmVnYXRlcyIsIHN0amEgPjApICU+JSAKICBnZ3Bsb3QoYWVzKHN0amEpKSArIGdlb21faGlzdG9ncmFtKGJpbnMgPSAyMCkgKyBzY2FsZV94X2xvZzEwKCkKYGBgCmBgYHtyfQpkZl9zdGphICU+JSBmaWx0ZXIoaW5jb21lICE9ICJBZ2dyZWdhdGVzIiwgaW5jb21lICE9ICJOb3QgY2xhc3NpZmllZCIsIHN0amEgPjApICU+JSAKICBnZ3Bsb3QoYWVzKHN0amEsIGZpbGwgPSBpbmNvbWUpKSArIGdlb21faGlzdG9ncmFtKGFscGhhID0gMC43LCBiaW5zID0gMjAsIGNvbG9yID0gImJsYWNrIikgKyBzY2FsZV94X2xvZzEwKCkKYGBgCgpgYGB7cn0KZGZfc3RqYSAlPiUgZmlsdGVyKGluY29tZSAhPSAiQWdncmVnYXRlcyIsIGluY29tZSAhPSAiTm90IGNsYXNzaWZpZWQiLCBzdGphID4wKSAlPiUgCiAgZ2dwbG90KGFlcyhzdGphLCBmaWxsID0gaW5jb21lKSkgKyBnZW9tX2RlbnNpdHkoYWxwaGEgPSAwLjMpICsgc2NhbGVfeF9sb2cxMCgpCmBgYAoKYGBge3J9CndkaV9jYWNoZSRzZXJpZXMgJT4lIGZpbHRlcihpbmRpY2F0b3IgPT0gIk1TLk1JTC5YUE5ELkdELlpTIikgJT4lIHB1bGwobmFtZSkKZGZfbWlseHBuZCA8LSBXREkoaW5kaWNhdG9yID0gYyhtaWx4cG5kID0gIk1TLk1JTC5YUE5ELkdELlpTIiksIGV4dHJhID0gVFJVRSkgJT4lCiAgZHJvcF9uYShtaWx4cG5kKQpgYGAKCgpEZWZhdWx0IG9mIHRoZSBudW1iZXIgb2YgYmlucyBpcyAzMC4gSGVyZSBJIGNob3NlIGJpbndpZHRoID0gMC41ICglKS4KCmBgYHtyfQpkZl9taWx4cG5kICU+JSBmaWx0ZXIoaW5jb21lICE9ICJBZ2dyZWdhdGVzIiwgeWVhciA9PSAyMDIxKSAlPiUgCiAgZ2dwbG90KGFlcyhtaWx4cG5kLCBmaWxsID0gaW5jb21lKSkgKyBnZW9tX2hpc3RvZ3JhbShjb2xvciA9ICJibGFjayIsIGJpbndpZHRoID0gMC41KSArIAogIGxhYnModGl0bGUgPSAiTWlsaXRhcnkgZXhwZW5kaXR1cmUgKCUgb2YgR0RQKSIpCmBgYAoKYGBge3J9CmRmX21pbHhwbmQgJT4lIGZpbHRlcihpbmNvbWUgIT0gIkFnZ3JlZ2F0ZXMiLCBpbmNvbWUgIT0gIk5vdCBjbGFzc2lmaWVkIiwgeWVhciA9PSAyMDIxKSAlPiUgCiAgZ2dwbG90KGFlcyhtaWx4cG5kLCBmaWxsID0gaW5jb21lKSkgKyBnZW9tX2RlbnNpdHkoYmlud2lkdGggPSAwLjUsIGFscGhhID0gMC4zKSArIAogIGxhYnModGl0bGUgPSAiTWlsaXRhcnkgZXhwZW5kaXR1cmUgKCUgb2YgR0RQKSIpCmBgYAoKIyMgUTIuIEVmZmVjdCBvZiB1bmVtcGxveWVkIHJhdGUgdW5kZXIgcGFuZGVtaWMgZGVwZW5kaW5nIG9uIGluY29tZSBncm91cHMKCmBgYHtyfQp3ZGlfY2FjaGUkc2VyaWVzICU+JSBmaWx0ZXIoaW5kaWNhdG9yID09ICJTTC5VRU0uVE9UTC5aUyIpICU+JSBwdWxsKG5hbWUpCmRmX3VyIDwtIFdESShpbmRpY2F0b3IgPSBjKHVyID0gIlNMLlVFTS5UT1RMLlpTIiksIAogICAgICAgICAgICAgZXh0cmEgPSBUUlVFLCBjYWNoZSA9IHdkaV9jYWNoZSkgJT4lIGRyb3BfbmEodXIpCmBgYAoKCmBgYHtyfQpkZl91ciAlPiUgZmlsdGVyKGluY29tZSA9PSAiQWdncmVnYXRlcyIpICU+JSBmaWx0ZXIoZ3JlcGwoJ2luY29tZScsIGNvdW50cnkpKSAlPiUgCiAgZmlsdGVyKHllYXIgPj0gMjAxOCkgJT4lIGdncGxvdCgpICsgZ2VvbV9saW5lKGFlcyh4ID0geWVhciwgeSA9IHVyLCBjb2xvciA9IGNvdW50cnkpKQpgYGAKCiMjIFEzLiBBZGQgdmFsdWVzIGF0IGVhY2ggZGF0YSBwb2ludC4KCmBgYHtyfQp3ZGlfY2FjaGUkc2VyaWVzICU+JSBmaWx0ZXIoaW5kaWNhdG9yID09ICJGUC5DUEkuVE9UTC5aRyIpICU+JSBwdWxsKG5hbWUpCmRmX2luZmwgPC0gV0RJKGNvdW50cnkgPSBjKCJWTiIsIkNOIiwiSlAiKSwgCiAgICAgICAgICAgICAgIGluZGljYXRvciA9IGMoaW5mID0gIkZQLkNQSS5UT1RMLlpHIiksIGV4dHJhID0gVFJVRSkgJT4lIGRyb3BfbmEoaW5mKQpgYGAKCmBgYHtyfQpkZl9pbmZsICU+JSBmaWx0ZXIoeWVhciAlaW4lIGMoMjAwMCwgMjAwNywgMjAyMCksIAogICAgICAgICAgICAgICAgICAgY291bnRyeSAlaW4lIGMoIkphcGFuIiwgIlZpZXRuYW0iLCAiQ2hpbmEiKSkgJT4lCiAgZ2dwbG90KGFlcyh4ID0geWVhciwgeSA9IGluZiwgY29sb3I9IGNvdW50cnkpKSArIAogIGdlb21fbGluZSgpICsgZ2VvbV9wb2ludCgpICsgCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHNjYWxlczo6bGFiZWxfcGVyY2VudChhY2N1cmFjeT0xKShpbmYpKSwgbnVkZ2VfeSA9IDAuOCkgKyAKbGFicyh0aXRsZSA9ICJJbmZsYXRpb24gb2YgSmFwYW4sIFZpZXRuYW0gYW5kIENoaW5hIGZyb20gMjAwMCB0byAyMDIwIiwgCiAgICAgeCA9ICIiLCB5ID0gIkluZmxhdGlvbiwgY29uc3VtZXIgcHJpY2VzIChhbm51YWwgJSkiKQpgYGAKCiMgUmVncmVzc2lvbiBMaW5lczsgVG9waWMgb2YgRURBNQoKYGBge3J9CndkaV9jYWNoZSRzZXJpZXMgJT4lIGZpbHRlcihpbmRpY2F0b3IgJWluJSBjKCJTSS5QT1YuTkFIQyIsIlNJLlBPVi5NRElNIikpICU+JSBwdWxsKG5hbWUpCmRmX3dkaV9wb3ZlcnR5IDwtIFdESSgKICBpbmRpY2F0b3IgPSBjKHBvdmVydHkgPSAiU0kuUE9WLk5BSEMiLCBtdWx0aXBvdmVydHkgPSAiU0kuUE9WLk1ESU0iLCBnZHBwZXJjYXAgPSAiTlkuR0RQLlBDQVAuS0QiKSwgc3RhcnQgPSAxOTkwLAogIGV4dHJhID0gVFJVRSkgJT4lIGRyb3BfbmEocG92ZXJ0eSwgbXVsdGlwb3ZlcnR5LCBnZHBwZXJjYXApCmBgYAoKYGBge3J9CmRmX3dkaV9wb3ZlcnR5ICU+JSAgCiAgZ3JvdXBfYnkoY291bnRyeSwgeWVhcikgJT4lCiAgbXV0YXRlKG1lYW5fZ2RwID0gbWVhbihnZHBwZXJjYXApKSAlPiUKICBtdXRhdGUobWVhbl9wb3ZlcnR5PSBtZWFuKHBvdmVydHkpKSAlPiUKICB1bmdyb3VwKCkgJT4lIGZpbHRlcihpbmNvbWUgIT0gIkFnZ3JlZ2F0ZXMiKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gbWVhbl9nZHApKSArIGdlb21fcG9pbnQoYWVzKHkgPSBtZWFuX3BvdmVydHksIGNvbG9yID0gaW5jb21lKSkgKwogIHNjYWxlX3hfbG9nMTAoKSArICBnZW9tX3Ntb290aChhZXMoeSA9IG1lYW5fcG92ZXJ0eSksIGZvcm11bGEgPSB5fngsIGxpbmV0eXBlPSJsb25nZGFzaCIsIGNvbG9yID0gImJsYWNrIiwgbWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSkgKyAKICBsYWJzKHggPSAiR0RQIHBlciBjYXBpdGEiLCB5ID0gInBvdmVydHkgcmF0ZSAoJSBvZiBwb3B1bGF0aW9uKSIsIHRpdGxlID0gIlBvdmVydHkgcmF0ZXMgYW5kIEdEUCBwZXIgY2FwaXRhIiwgc3VidGl0bGU9IndvcmxkIGNvdW50cmllcywgMTk5MC0yMDIxIGF2ZXJhZ2UsIGJ5IGluY29tZSBsZXZlbCIpCmBgYAoKYGBge3J9CmRmX3dkaV9wb3ZlcnR5ICU+JSAgCiAgZ3JvdXBfYnkoY291bnRyeSwgeWVhcikgJT4lCiAgbXV0YXRlKG1lYW5fZ2RwID0gbWVhbihnZHBwZXJjYXApKSAlPiUKICBtdXRhdGUobWVhbl9tdWx0aXBvdmVydHk9IG1lYW4obXVsdGlwb3ZlcnR5KSkgJT4lCiAgdW5ncm91cCgpICU+JQogICAgZmlsdGVyKHJlZ2lvbiAhPSJBZ2dyZWdhdGVzIikgJT4lIGdncGxvdChhZXMoeCA9IG1lYW5fZ2RwKSkgKyBnZW9tX3BvaW50KGFlcyh5ID0gbWVhbl9tdWx0aXBvdmVydHksIGNvbG9yID0gcmVnaW9uKSkgKyAgCiAgc2NhbGVfeF9sb2cxMCgpICsgIAogIGdlb21fc21vb3RoKGFlcyh5ID0gbWVhbl9tdWx0aXBvdmVydHkpLCBmb3JtdWxhID0geX54LCBsaW5ldHlwZT0ibG9uZ2Rhc2giLCBjb2xvciA9ICJibGFjayIsIG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UpICsgbGFicyh4ID0gIkdEUCBwZXIgY2FwaXRhIiwgeSA9ICJNdWx0aWRpbWVudGluYWwgcG92ZXJ0eSByYXRlICglIG9mIHBvcHVsYXRpb24pIiwgdGl0bGUgPSAiTXVsdGlkaW1lbnRpb25hbCBQb3ZlcnR5IHJhdGVzIGFuZCBHRFAgcGVyIGNhcGl0YSIsIHN1YnRpdGxlPSJ3b3JsZCBjb3VudHJpZXMsIDE5OTAtMjAyMSBhdmVyYWdlLCBieSByZWdpb24iKQpgYGAKCgojIEFwcGVuZGl4OiBBIHNlY29uZGFyeSBheGlzCgoqIFtTcGVjaWZ5IGEgc2Vjb25kYXJ5IGF4aXNdKGh0dHBzOi8vZ2dwbG90Mi50aWR5dmVyc2Uub3JnL3JlZmVyZW5jZS9zZWNfYXhpcy5odG1sKQogIC0gVGhpcyBmdW5jdGlvbiBpcyB1c2VkIGluIGNvbmp1bmN0aW9uIHdpdGggYSBwb3NpdGlvbiBzY2FsZSB0byBjcmVhdGUgYSBzZWNvbmRhcnkgYXhpcywgcG9zaXRpb25lZCBvcHBvc2l0ZSBvZiB0aGUgcHJpbWFyeSBheGlzLiBBbGwgc2Vjb25kYXJ5IGF4ZXMgbXVzdCBiZSBiYXNlZCBvbiBhIG9uZS10by1vbmUgdHJhbnNmb3JtYXRpb24gb2YgdGhlIHByaW1hcnkgYXhlcy4KCmBzY2FsZV95X2NvbnRpbnVvdXMoc2VjLmF4aXMgPSBzZWNfYXhpcyh+IC4gc2NhbGluZ19mdW5jdGlvbikpYAoKIyMgRXhhbXBsZQoKU3VwcG9zZSB5b3UgaGF2ZSB0d28gaW5kaWNhdG9ycywgCgoqIE5ZLkdEUC5NS1RQLktEOiBHRFAgKGNvbnN0YW50IDIwMTUgVVMkKQoqIE5ZLkdEUC5QQ0FQLktEOiBHRFAgcGVyIGNhcGl0YSAoY29uc3RhbnQgMjAxNSBVUyQpCgpgYGB7cn0KV0RJc2VhcmNoKHN0cmluZyA9ICJOWS5HRFAuTUtUUC5LRCIsIGZpZWxkID0gImluZGljYXRvciIsIHNob3J0ID0gRkFMU0UsIGNhY2hlID0gd2RpX2NhY2hlKQpgYGAKCmBgYHtyfQpXRElzZWFyY2goc3RyaW5nID0gIk5ZLkdEUC5QQ0FQLktEIiwgZmllbGQgPSAiaW5kaWNhdG9yIiwgc2hvcnQgPSBGQUxTRSwgY2FjaGUgPSB3ZGlfY2FjaGUpCmBgYAoKTGlzdCB0aGUgbmFtZSBvZiBjb3VudHJpZXMgb2YgQVNFQU4gYW5kIEJSSUNzIHVzaW5nIGB3ZGlfY2FjaGUkY291bnRyeWAuCgpgYGB7cn0KYXNlYW4gPC0gYygiQnJ1bmVpIERhcnVzc2FsYW0iLCAiQ2FtYm9kaWEiLCAiTGFvIFBEUiIsICJNeWFubWFyIiwgCiAgICAgICAgICAgIlBoaWxpcHBpbmVzIiwgIkluZG9uZXNpYSIsICJNYWxheXNpYSIsICJTaW5nYXBvcmUiKQpicmljcyA8LSBjKCJCcmF6aWwiLCAiUnVzc2lhbiBGZWRlcmF0aW9uIiwgIkluZGlhIiwgIkNoaW5hIikKYGBgCgpGaW5kIHRoZSBgaXNvMmNgIG9mIHRoZSBjb3VudHJpZXMgdXNpbmcgYHdkaV9jYWNoZSRjb3VudHJ5YC4KCmBgYHtyfQp3ZGlfY2FjaGUkY291bnRyeSAlPiUgCiAgZmlsdGVyKGNvdW50cnkgJWluJSAKICAgICAgICAgICBjKCJCcnVuZWkgRGFydXNzYWxhbSIsICJDYW1ib2RpYSIsICJMYW8gUERSIiwgIk15YW5tYXIiLCAKICAgICAgICAgICAiUGhpbGlwcGluZXMiLCAiSW5kb25lc2lhIiwgIk1hbGF5c2lhIiwgIlNpbmdhcG9yZSIsCiAgICAgICAgICAgIkJyYXppbCIsICJSdXNzaWFuIEZlZGVyYXRpb24iLCAiSW5kaWEiLCAiQ2hpbmEiKSkgJT4lIAogIHB1bGwoaXNvMmMpCmBgYAoKU2VwYXJhdGUgdGhlIGlzbzNjJ3Mgb2YgdGhlIGNvdW50cmllcyB3aXRoIGNvbW1hcyBhbmQgcmVhZCBkYXRhIHVzaW5nIGBXRElgLgoKYGBge3IgY2FjaGU9VFJVRX0Kd2RpX2dkcCA8LSBXREkoCiAgY291bnRyeSA9IGMoIkJSIiwgIkJOIiwgIkNOIiwgIklEIiwgIklOIiwgIktIIiwgIkxBIiwgIk1NIiwgIk1ZIiwgIlBIIiwgIlJVIiwgIlNHIiksCiAgaW5kaWNhdG9yID0gYyhnZHAgPSAiTlkuR0RQLk1LVFAuS0QiLCBnZHBQZXJjYXAgPSAiTlkuR0RQLlBDQVAuS0QiKSwKICBzdGFydCA9IDE5NjAsIGV4dHJhID0gVFJVRSwgY2FjaGUgPSB3ZGlfY2FjaGUpCmBgYAoKCmBgYHtyfQp3ZGlfZ2RwICU+JSBmaWx0ZXIoY291bnRyeSAlaW4lIGFzZWFuKSAlPiUgZHJvcF9uYShnZHAsIGdkcFBlcmNhcCkgJT4lIHN1bW1hcnkoKSAKYGBgCgpVc2luZyB0aGUgc3VtbWFyeSwgZGVjaWRlIHRoZSBzY2FsaW5nIG9mIHR3byB2YXJpYWJsZXMsIGBnZHBQZXJjYXBgIGFuZCBgZ2RwYC4KCmBgYHtyfQp3ZGlfZ2RwICU+JSBkcm9wX25hKGdkcCwgZ2RwUGVyY2FwKSAlPiUKICBmaWx0ZXIoY291bnRyeSAlaW4lIGFzZWFuKSAlPiUKICBnZ3Bsb3QoKSArIAogIGdlb21fbGluZShhZXMoeCA9IHllYXIsIHkgPSBnZHBQZXJjYXAsIGxpbmV0eXBlID0gY291bnRyeSkpICsgCiAgZ2VvbV9saW5lKGFlcyh4ID0geWVhciwgeSA9IGdkcC8oMTBeNyksIGNvbCA9IGNvdW50cnkpKSArIAogIGNvb3JkX3RyYW5zKHggPSJpZGVudGl0eSIsIHk9ImxvZzEwIikgKwogIHNjYWxlX3lfY29udGludW91cyhzZWMuYXhpcyA9IHNlY19heGlzKH4gLiAqKDEwXjcpLCBuYW1lID0gImdkcC8oMTBeNykiKSkKYGBgCgojIyMgQlJJQ3MKCmBgYHtyfQp3ZGlfZ2RwICU+JSBmaWx0ZXIoY291bnRyeSAlaW4lIGJyaWNzKSAlPiUgZHJvcF9uYShnZHAsIGdkcFBlcmNhcCkgJT4lIHN1bW1hcnkoKSAKYGBgCgpVc2luZyB0aGUgc3VtbWFyeSwgZGVjaWRlIHRoZSBzY2FsaW5nIG9mIHR3byB2YXJpYWJsZXMsIGBnZHBQZXJjYXBgIGFuZCBgZ2RwYC4KCmBgYHtyfQp3ZGlfZ2RwICU+JSBkcm9wX25hKGdkcCwgZ2RwUGVyY2FwKSAlPiUKICBmaWx0ZXIoY291bnRyeSAlaW4lIGJyaWNzKSAlPiUKICBnZ3Bsb3QoKSArIAogIGdlb21fbGluZShhZXMoeCA9IHllYXIsIHkgPSBnZHBQZXJjYXAsIGxpbmV0eXBlID0gY291bnRyeSkpICsgCiAgZ2VvbV9saW5lKGFlcyh4ID0geWVhciwgeSA9IGdkcC8oMTBeOSksIGNvbCA9IGNvdW50cnkpKSArIAogIGNvb3JkX3RyYW5zKHggPSJpZGVudGl0eSIsIHk9ImxvZzEwIikgKwogIHNjYWxlX3lfY29udGludW91cyhzZWMuYXhpcyA9IHNlY19heGlzKH4gLiAqKDEwXjcpLCBuYW1lID0gImdkcC8oMTBeOSkiKSkKYGBgCgoKCgoK